#include "JobQueue.h"

void jobqueue_init(JobQueue* q)
{
    q->front = NULL;
    q->rear = NULL;
    q->size = 0;
    pthread_mutex_init(&q->mutex, NULL);
    bsem_init(&q->has_jobs, 0);
}

void jobqueue_push(JobQueue* q, Job* job)
{
    pthread_mutex_lock(&q->mutex);
    if (q->size) {
        q->rear->next = job;
        q->rear = job;
    } else {
        q->front = job;
        q->rear = job;
    }
    q->size++;
    // 添加元素，队列中有任务了
    bsem_post(&q->has_jobs);    // 唤醒其它线程
    pthread_mutex_unlock(&q->mutex);
}

// 没有任务，返回 NULL
Job* jobqueue_pop(JobQueue* q) 
{
    pthread_mutex_lock(&q->mutex);
    Job* job = q->front;

    switch (q->size) {
    case 0: /* no jobs */
        bsem_reset(&q->has_jobs);
        break;
    case 1: 
        q->front = NULL;
        q->rear = NULL;
        q->size = 0;
        bsem_reset(&q->has_jobs);   
        break;
    default: /* more than 1 jobs */
        q->front = job->next;
        q->size--;
        bsem_post(&q->has_jobs); // 没有采用 bsem_postall, 线程只能一个一个去任务队列拿任务
        break;
    }
    pthread_mutex_unlock(&q->mutex);
    return job;
}

// 清空任务，不执行任务
void jobqueue_clear(JobQueue* q) 
{
    pthread_mutex_lock(&q->mutex);
    Job* curr = q->front;
    while (curr) {
        Job* next = curr->next;
        free(curr);
        curr = next;
    } // curr == NULL
    // 将 JobQueue 重新置为空的状态
    q->front = NULL;
    q->rear = NULL;
    q->size = 0;
    bsem_reset(&q->has_jobs);
    pthread_mutex_unlock(&q->mutex);
}

void jobqueue_destroy(JobQueue* q)
{
    // 清空任务
    jobqueue_clear(q);
    // 销毁互斥锁
    pthread_mutex_destroy(&q->mutex);
    // 销毁二元信号量
    bsem_destroy(&q->has_jobs);
}


#ifdef JOBQUEUE_TEST

void* start_routine(void* arg)
{
    JobQueue* q = (JobQueue*) arg;
    for(;;) {
        bsem_wait(&q->has_jobs);
        Job* job = jobqueue_pop(q);
        if (job) {
            // 执行任务
            job->function(job->arg);
            free(job);
        }
    }
}

void task(void* arg)
{
    int id = (int) arg;
    printf("#%lx: execute task %d\n", pthread_self(), id);
    sleep(1);   // 模拟执行任务
    printf("#%lx: task %d done\n", pthread_self(), id);
}

int main(int argc, char* argv[])
{
    // 主线程
    JobQueue q;
    jobqueue_init(&q);

    // 创建线程
    pthread_t tid1, tid2;
    pthread_create(&tid1, NULL, start_routine, (void*)&q);
    pthread_create(&tid2, NULL, start_routine, (void*)&q);

    sleep(3);

    // 主线程添加任务
    for (int i = 1; i <= 10; i++) {
        // 创建并初始化 Job
        Job* job = malloc(sizeof(Job));
        job->function = task;
        job->arg = (void*)i;
        job->next = NULL;

        jobqueue_push(&q, job);
    }

    // 主线程等待子线程结束
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);

    return 0;
}
#endif
